/**
 *
 */
package com.acme.bankapp.service.email;

import java.util.LinkedList;
import java.util.List;

import com.acme.bankapp.service.email.exception.AddAfterCloseQueueException;
import com.acme.bankapp.service.email.exception.GetAfterCloseQueueException;

/**
 * @author nulls.narik
 */
public class Queue<T> {

	private final int maxCount;

	public Queue(int maxCount) {
		this.maxCount = maxCount;
		items = new LinkedList<T>();
		closing = false;
	}

	private List<T> items;

	public T get() throws GetAfterCloseQueueException {
		synchronized (items) {
			try {
				while (!closing && items.isEmpty()) {
					items.wait();
				}
			} catch (InterruptedException e) { }

			if (closing && items.isEmpty()) {
				items.notifyAll();
				throw new GetAfterCloseQueueException();
			} else {
				T item = items.remove(0);
				items.notifyAll();
				return item;
			}
		}
	}

	public void add(T item) throws AddAfterCloseQueueException {
		synchronized (items) {
			try {
				while (!closing && (items.size() >= maxCount)) {
					items.wait();
				}
			}
			catch (InterruptedException e) { }


			if (closing && (items.size() >= maxCount)) {
				items.notifyAll();
				throw new AddAfterCloseQueueException();
			} else {
				items.add(item);
				items.notifyAll();
			}
		}
	}

	public boolean isEmpty() {
		synchronized (items) {
			return items.isEmpty();
		}
	}

	private boolean closing;

	public void close() {
		synchronized (items) {
			closing = true;
			items.notifyAll();
		}
	}

	public boolean isClosing() {
		return closing;
	}

}
